home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
001
/
cardfile.arc
/
CARDFILE.ASM
next >
Wrap
Assembly Source File
|
1987-09-14
|
93KB
|
1,899 lines
page 60,132
;CARDFILE.COM for the IBM Personal Computer - 1987 by Jeff Prosise
;
bios_data segment at 40h
rs232_base dw 4 dup (?) ;UART base addresses
org 4Ah
crt_cols dw ? ;number of display columns
org 4Eh
crt_start dw ? ;video page offset address
org 63h
addr_6845 dw ? ;CRTC base address
org 87h
infobyte label word
ega_info db ? ;EGA info byte
bios_data ends
;
code segment para public 'code'
assume cs:code
org 100h
begin: jmp init1 ;goto initialization code
;
program db "Cardfile 1.0 "
copyright db "(c) 1987 Ziff Communications Co.",13,10
db "Hotkey is ALT-RIGHT SHIFT$",1Ah
author db "Jeff Prosise"
;
dos_segment dw ? ;segment of internal DOS flags
indos_offset dw ? ;offset of INDOS flag
errflag_offset dw ? ;offset of critical error flag
program_status db 0 ;popup status
flag_10h db 0 ;status of interrupt 10h
flag_13h db 0 ;status of interrupt 13h
request_flag db 0 ;status of processing request
ss_register dw ? ;SS register storage
sp_register dw ? ;SP register storage
oldpsp dw ? ;PSP segment storage
;
maxrec db 255 ;maximum number of records
recptr db 1 ;current record number
numrec db 0 ;number of records
adapter db ? ;0=MDA, 1=CGA, 2=EGA
video_segment dw ? ;video segment address
border_attr db ? ;window border attribute
text_attr db ? ;window text attribute
menu_attr db ? ;menu line attribute
record_attr db ? ;record display attribute
video_page db ? ;current video page
cursor_mode dw ? ;cursor shape
cursor_pos dw ? ;cursor position
cursor_addr dw ? ;cursor CRTC address
new_cursor dw ? ;Cardfile cursor shape
dos_version db ? ;DOS version number
slotno db ? ;record position
reload db ? ;reload data file flag
zflag db ? ;critical error flag change status
fileflag db 0 ;filespec validity indicator
record_length db 192 ;record length in bytes
;
comport dw 0 ;COM1
initstr db 10000011b ;1200 baud, N81 data format
dialstr db "ATDT",0 ;Hayes Smartmodem dial string
hangupstr db "ATH0",13,0 ;Hayes Smartmodem hangup string
;
jump_table dw offset create ;vector dispatch table
dw offset edit
dw offset delete
dw offset search
dw offset save
dw offset dial
;
titles db 32,"Name",32,32,"Addr",14 dup (32),"Phone",32,"Note",32
menuline1 db "F1-New F2-Ed F3-Del F4-Sch F5-Sv F6-Dial",0
menuline2 db "Press ENTER to delete, ESC to abort",0
menuline3 db "Press F1 to validate new entry",0
menuline4 db "Find:",0
menuline5 db "Press ENTER to continue, ESC to end",0
menuline6 db "Search key not found. Press ESC",0
menuline7 db "No room for additional records",0
menuline8 db "Disk full",0
menuline9 db "Press F1 to validate changes",0
menuline10 db "Pick up phone and press spacebar",0
menuline11 db "Error saving file",0
menuline12 db "Modem not ready",0
menuline13 db "File:",0
;
timer_int label dword ;old interrupt 8 vector
old8h dw 2 dup (?)
keyboard_int label dword ;old interrupt 9 vector
old9h dw 2 dup (?)
video_int label dword ;old interrupt 10h vector
old10h dw 2 dup (?)
bdisk_int label dword ;old interrupt 13h vector
old13h dw 2 dup (?)
bp_int label dword ;old interrupt 28h vector
old28h dw 2 dup (?)
;
old1Bh_segment dw ? ;old interrupt 1Bh segment
old1Bh_offset dw ? ;old interrupt 1Bh offset
old23h_segment dw ? ;old interrupt 23h segment
old23h_offset dw ? ;old interrupt 23h offset
old24h_segment dw ? ;old interrupt 24h segment
old24h_offset dw ? ;old interrupt 24h offset
;
color_attr db 0,0B8h,1Fh,6Eh,6Eh,6Fh
mono_attr db 0,0B0h,70h,07h,07h,07h
enable_values db 2Ch,28h,2Dh,29h,2Ah,2Eh,1Eh
key_table db "QWERTYUIOP",0,0,0,0
db "ASDFGHJKL",0,0,0,0,0
db "ZXCVBNM"
;
;------------------------------------------------------------------------------
;Execution comes here thru interrupt 9 every time a key is pressed or released.
;------------------------------------------------------------------------------
keyboard proc near
sti ;set interrupt enable flag
pushf ;push flags to simulate INT
call keyboard_int ;call keyboard handling routine
push ax ;save AX
mov ah,2 ;get keyboard shift status
int 16h
and al,0Fh ;mask off upper 4 bits
cmp al,9 ;Alt/Rt-Shift pressed?
pop ax ;restore AX
jne kb_exit ;no, then exit
cmp program_status,0 ;popup routine already active?
jne kb_exit ;yes, then ignore keypress
mov request_flag,18 ;set request flag
kb_exit: iret
keyboard endp
;
;------------------------------------------------------------------------------
;Interrupt 8 handling routine.
;------------------------------------------------------------------------------
timer proc near
pushf ;call BIOS routine
call timer_int
cmp request_flag,0 ;flag set?
je timer_exit ;no, then exit
cmp flag_10h,0 ;video flag set?
jne dectime ;yes, then exit
cmp flag_13h,0 ;disk flag set?
jne dectime ;yes, then exit
push es ;save ES and DI
push di
mov es,dos_segment ;check INDOS flag
mov di,indos_offset
cmp byte ptr es:[di],0
jne poptime ;exit if it's set
mov di,errflag_offset ;check critical error flag
cmp byte ptr es:[di],0
jne poptime ;exit if it's set
pop di ;restore registers
pop es
mov request_flag,0 ;zero request flag
call main ;call body of program
timer_exit: iret
poptime: pop di ;clean up the stack
pop es
dectime: dec request_flag ;decrement request flag
iret
timer endp
;
;------------------------------------------------------------------------------
;Interrupt 10h handling routine.
;------------------------------------------------------------------------------
video proc near
pushf ;push flags onto stack
inc flag_10h ;increment flag
call video_int ;call BIOS routine
dec flag_10h ;decrement flag
iret
video endp
;
;------------------------------------------------------------------------------
;Interrupt 13h handling routine.
;------------------------------------------------------------------------------
bdisk proc far
pushf ;push flags onto stack
inc flag_13h ;set 'busy' flag
call bdisk_int ;call BIOS routine
pushf ;save output flags
dec flag_13h ;clear flag
popf ;restore output flags
ret 2 ;exit without destroying flags
bdisk endp
;
;------------------------------------------------------------------------------
;Interrupt 28h handling routine.
;------------------------------------------------------------------------------
backproc proc near
pushf ;call original routine
call bp_int
cmp request_flag,0 ;request flag clear?
je bp_exit ;yes, then exit
cmp flag_10h,0 ;video flag set?
jne bp_exit ;yes, then exit
cmp flag_13h,0 ;disk flag set?
jne bp_exit ;yes, then exit
push es ;save ES and DI
push di
mov es,dos_segment ;check critical error flag
mov di,errflag_offset
cmp byte ptr es:[di],0
pop di ;clean up the stack
pop es
jne bp_exit
mov request_flag,0 ;clear request flag
call main ;call main routine
bp_exit: iret ;done - exit
backproc endp
;
;------------------------------------------------------------------------------
;Interrupt 24h handling routine (DOS 3.X only).
;------------------------------------------------------------------------------
ioerr proc near
mov al,3 ;fail the call in progress
ioexit: iret ;give control back to DOS
ioerr endp
;
;------------------------------------------------------------------------------
;MAIN is the routine called to pop up and manipulate the CardFile window.
;------------------------------------------------------------------------------
main proc near
mov program_status,1 ;set program active flag
cli ;make sure interrupts are off
mov ss_register,ss ;save stack registers
mov sp_register,sp
push cs ;switch to internal stack
pop ss
mov sp,offset filespec
sti ;enable interrupts
push ax ;save other registers
push bx
push cx
push dx
push si
push di
push ds
push es
push bp
mov ah,15 ;get video mode and page
int 10h
cmp al,3 ;mode 0, 1, 2, or 3?
jbe main1 ;yes, then continue
cmp al,7 ;mode 7?
je main1 ;yes, then continue
;
;Restore registers and stack before exit.
;
exit: pop bp ;restore registers and exit
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
cli ;interrupts off
mov ss,ss_register ;switch to original stack
mov sp,sp_register
sti ;interrupts on
mov program_status,0 ;clear status flag
ret
;
;Set DS and ES segment registers.
;
main1: push cs ;set DS to code segment
pop ds
assume ds:code
mov ax,bios_data ;point ES to BIOS data
mov es,ax
assume es:bios_data
cmp crt_cols,80 ;at least 80 columns displayed?
jb exit ;no, then exit
;
;Save needed video parameters.
;
mov video_page,bh ;active video page
mov ah,3 ;get cursor mode and location
int 10h
mov cursor_mode,cx
mov cursor_pos,dx
mov dx,addr_6845 ;get CRTC base address
push dx ;save it for later
mov al,14 ;specify register number
out dx,al
inc dx ;point DX to data port
in al,dx ;read high byte of address
mov ah,al ;save it
dec dx ;back to index register
mov al,15 ;specify register number
out dx,al
inc dx ;back to data port
in al,dx ;read low byte of address
mov cursor_addr,ax ;save cursor address
;
;Determine whether an EGA is present and active in the system.
;
mov ah,12h ;see if EGA is present
mov bl,10h
int 10h
cmp bl,10h ;did BL return unchanged?
je main2 ;yes, then there's no EGA here
test ega_info,8 ;is the EGA currently active?
jnz main2 ;no, then branch
mov adapter,2 ;set ADAPTER for EGA
push bx ;save BX
mov ax,1130h ;get number of scan lines per char
int 10h
dec cl ;form cursor definition in CX
mov ch,cl
sub ch,2
mov new_cursor,cx ;save cursor definition
mov si,offset color_attr ;point SI to color parms
pop bx ;retrieve BX
or bh,bh ;EGA attached to color monitor?
je main4 ;yes, then branch
mov si,offset mono_attr ;no, then point SI to mono parms
jmp short main4
;
;Determine whether the active video adapter is a CGA or an MDA.
;
main2: test addr_6845,40h ;is bit 6 of the CRTC address set?
jz main3 ;no, then it's monochrome
mov adapter,1 ;set ADAPTER for a CGA
mov new_cursor,0607h ;define cursor shape
mov si,offset color_attr ;point SI to color parms
jmp short main4
main3: mov adapter,0 ;set ADAPTER for an MDA
mov new_cursor,0B0Ch ;define monochrome cursor
mov si,offset mono_attr ;point SI to mono parms
;
;Set video parameters for color or monochrome.
;
main4: push cs ;set ES to the code segment
pop es
assume es:nothing
mov di,offset video_segment ;point DI to destination
mov cx,3 ;3 words to move
cld ;clear DF
rep movsw ;transfer the values
;
;Save the current active PSP address and activate this PSP.
;
push es ;save ES
mov zflag,0 ;clear flag
cmp dos_version,2 ;DOS version 2.X?
jne main5
mov es,dos_segment ;point ES:DI to INDOS
mov di,indos_offset
cmp byte ptr es:[di],0 ;INDOS clear?
je main5 ;yes, then branch
mov di,errflag_offset ;point ES:DI to error flag
cmp byte ptr es:[di],0 ;critical error flag clear?
jne main5 ;no, then branch
mov byte ptr es:[di],1 ;set critical error flag manually
mov zflag,1 ;set change flag
main5: mov ah,51h ;get current PSP segment
int 21h
mov oldpsp,bx ;save it
mov ah,50h ;make this the active PSP
push cs
pop bx
int 21h
cmp zflag,0 ;ZFLAG clear?
je main6 ;yes, then branch
mov di,errflag_offset ;point ES:DI to error flag
mov byte ptr es:[di],0 ;restore error flag value
main6: pop es ;restore ES
;
;Reset the interrupt 1Bh, 23h, and 24h vectors and open the CardFile window.
;
call ioset ;reset interrupt vectors
cmp adapter,1 ;disable CGA video
jne main7
call disable_cga
main7: call save_screen ;save memory to be overwritten
call make_screen ;open the CardFile window
cmp adapter,1 ;enable CGA video
jne main8
call enable_cga
main8: mov ah,1 ;hide the cursor
mov ch,20h
int 10h
cmp numrec,0 ;any records in memory?
je main10 ;no, then branch
call show_record ;display current record
;
;Wait for a keystroke and exit when ESC is pressed.
;
main10: call getkey ;wait for a keypress
or al,al ;extended code entered?
je main12 ;yes, then branch
cmp al,13 ;ENTER pressed?
jne main11 ;no, then branch around
cmp numrec,2 ;at least 2 records?
jb main10 ;no, then ignore keypress
jmp short main20 ;yes, then do a PgDn
main11: cmp al,27 ;ESC pressed?
jne main10 ;no, then ignore keypress
jmp short escape ;yes, then close window and exit
;
;An extended code was entered. Check for an Alt-character key combination.
;
main12: cmp ah,16 ;scan code < 16 (Alt-Q)?
jb main10 ;yes, then ignore it
cmp ah,50 ;scan code > 50 (Alt-M)?
ja main13 ;yes, then branch and continue
call qsearch ;do quick search
jmp main10 ;return for another keypress
;
;Check for a press of any function key F1 through F6.
;
main13: cmp ah,59 ;scan code < 59 (F1)?
jb main10 ;yes, then ignore it
cmp ah,64 ;scan code > 64 (F6)?
ja main14 ;yes, then branch and continue
sub ah,59 ;normalize scan code
mov bl,ah ;transfer result
xor bh,bh ;byte to word in BX
shl bx,1 ;double index in BX
call word ptr cs:[offset jump_table+bx] ;call routine
jmp main10 ;return
;
;Check for Home, End, PgUp, and PgDn.
;
main14: cmp numrec,2 ;are there at least 2 records?
jb main10 ;no, then ignore keypress
cmp ah,71 ;Home key?
jne main16 ;no, then branch
mov recptr,1 ;set pointer to first record
main15: call show_record ;display record
jmp main10 ;return
main16: cmp ah,79 ;End key?
jne main18 ;no, then branch
main17: mov al,numrec ;get number of records
mov recptr,al ;set pointer to last record
jmp main15 ;display record
main18: cmp ah,73 ;PgUp key?
jne main19 ;no, then branch
dec recptr ;adjust pointer
cmp recptr,0 ;wrap around if necessary
jne main15
jmp main17
main19: cmp ah,81 ;PgDn key?
jne main10 ;no, then ignore keypress
main20: mov al,numrec ;presently showing last record?
cmp al,recptr
je main21 ;yes, then branch
inc recptr ;no, then advance pointer
jmp main15 ;display record
main21: mov recptr,1 ;set pointer to first record
jmp main15 ;display record
;
;Restore interrupt vectors and former active PSP.
;
escape: mov ah,50h ;restore active PSP label
mov bx,oldpsp
int 21h
call ioreset ;restore interrupt vectors
;
;Close the Cardfile window in preparation for exit.
;
cmp adapter,1 ;disable CGA video
jne esc1
call disable_cga
esc1: call restore_screen ;restore screen contents
cmp adapter,1 ;enable CGA video
jne esc2
call enable_cga
;
;Restore the cursor's former position in the BIOS data area and the CRTC.
;
esc2: mov ah,2 ;set cursor position thru BIOS
mov bh,video_page
mov dx,cursor_pos
int 10h
pop dx ;recover CRTC base address
mov cx,cursor_addr ;restore cursor address
mov al,14 ;CRTC register number
out dx,al
inc dx
mov al,ch
out dx,al ;write high byte of address
dec dx
mov al,15 ;CRTC register number
out dx,al
inc dx
mov al,cl
out dx,al ;write low byte
;
;Display the cursor, bypassing EGA cursor emulation logic, and exit.
;
cmp adapter,2 ;EGA on board?
jne esc3 ;no, then branch
call show_cursor ;retain current shape
jmp exit
esc3: mov ah,1 ;restore cursor shape
mov cx,cursor_mode
int 10h
jmp exit ;exit
main endp
;
;------------------------------------------------------------------------------
;SAVE_SCREEN saves the contents of the screen that underlie the window.
;------------------------------------------------------------------------------
linesum dw ?
video_address dw ?
;
save_screen proc near
push ds ;save DS
mov ax,bios_data ;point it to BIOS data area
mov ds,ax
assume ds:bios_data
mov ax,crt_cols ;get number of display columns
mov linesum,ax ;calculate distance from end of
sub linesum,44 ; one line to start of next
shl linesum,1
mov bl,6 ;calculate starting address
mul bl ;result in AX
shl ax,1 ;double result for attr bytes
add ax,36 ;add line offset
mov si,ax ;transfer to SI
add si,crt_start ;add page offset
mov video_address,si ;save offset address
mov ds,video_segment ;then set DS to the video segment
mov di,offset screen_buffer ;point DI to storage buffer
mov cx,10 ;10 lines to save
save1: push cx ;save line count
mov cx,44 ;44 characters per line
rep movsw ;transfer one line to storage
pop cx ;retrieve line count
add si,linesum ;point SI to next video line
loop save1 ;loop until all lines are saved
pop ds ;restore DS
assume ds:code
ret ;exit
save_screen endp
;
;------------------------------------------------------------------------------
;RESTORE_SCREEN writes the stored screen image to video memory.
;------------------------------------------------------------------------------
restore_screen proc near
push es ;save ES register value
mov di,video_address ;point DI to starting video offset
mov es,video_segment ;point ES to video memory
mov si,offset screen_buffer ;point DS:SI to screen image
mov cx,10 ;10 lines to restore
restore1: push cx ;save line count
mov cx,44 ;44 characters per line
rep movsw ;restore one line
pop cx ;retrieve line count
add di,linesum ;set DI to next video line
loop restore1 ;loop until done
pop es ;restore ES
ret
restore_screen endp
;
;------------------------------------------------------------------------------
;MAKE_SCREEN writes an image of the CardFile window to video memory.
;------------------------------------------------------------------------------
make_screen proc near
push es ;save ES
mov es,video_segment ;point ES:DI to video memory
mov di,video_address
mov al,218 ;line no. 1
mov ah,border_attr
stosw
mov al,196
mov cx,42
rep stosw
mov al,191
stosw
add di,linesum
mov si,offset titles ;lines 2 thru 7
mov cx,6 ;6 lines
make1: push cx
call formline
add di,linesum
pop cx
loop make1
mov al,179 ;line no. 8
stosw
push ax
mov al,32
mov ah,text_attr
stosw
push ax
mov al,196
mov cx,40
rep stosw
pop ax
stosw
pop ax
stosw
add di,linesum
stosw ;line no. 9
push ax
mov al,32
mov ah,menu_attr
stosw
push ax
mov si,offset menuline1
mov cx,40
make2: lodsb
stosw
loop make2
pop ax
stosw
pop ax
stosw
add di,linesum
mov al,192 ;line no. 10
stosw
mov al,196
mov cx,42
rep stosw
mov al,217
stosw
pop es ;restore ES
ret
make_screen endp
;
;------------------------------------------------------------------------------
;FORMLINE is called by MAKE_SCREEN to help with the dirty work.
;------------------------------------------------------------------------------
formline proc near
mov al,179 ;write border character
mov ah,border_attr
stosw
push ax ;save it for later
mov cx,6 ;do next 6 characters
mov ah,text_attr
form1: lodsb
stosw
loop form1
mov al,32 ;add 2 blanks
stosw
stosw
mov ah,record_attr ;then add 34 blank characters
mov cx,34
rep stosw
pop ax ;finish with border character
stosw
ret
formline endp
;
;------------------------------------------------------------------------------
;QSEARCH pages to the record whose first character matches the Alt key pressed.
;------------------------------------------------------------------------------
qsearch proc near
cmp numrec,2 ;at least 2 records to search?
jb qs3 ;no, then exit
mov al,ah ;transfer scan code to AL
sub al,16 ;normalize it
mov bx,offset key_table ;address table of equivalents
xlat ;get corresponding ASCII code
mov dl,al ;transfer it to DL
mov cl,numrec ;get record count in CX
xor ch,ch
mov al,1 ;initialize record index
qs1: push ax ;save index
push cx ;save count
call record_address ;get address of current record
cmp [di],dl ;compare characters
pop cx ;retrieve count and index
pop ax
jae qs2 ;end search
inc al ;increment index
loop qs1 ;loop back for next record
dec al ;search exhausted
qs2: cmp al,recptr ;record already showing?
je qs3 ;yes, then exit
mov recptr,al ;no, then change display
call show_record
qs3: ret
qsearch endp
;
;------------------------------------------------------------------------------
;SEARCH searches data for occurrence of a string input by the user.
;------------------------------------------------------------------------------
strlen db ? ;string length
passes db ? ;number of search loops
;
search proc near
cmp numrec,0 ;any records to search?
je search_exit ;no, then exit
mov si,offset menuline4 ;prepare menu line for input
call write_menu
xor di,di ;read string from keyboard
mov dx,0E1Ah
mov cl,32
call readln
or cl,cl ;anything entered?
jne search1 ;yes, then continue
search_exit: mov si,offset menuline1 ;restore menu line and exit
call write_menu
ret
;
;Set search parameters and begin the scan.
;
search1: mov strlen,cl ;save string length
mov ch,33 ;determine no. of passes per line
sub ch,cl
mov passes,ch ;save it
mov al,recptr ;start search at current record
mov cl,numrec ;set max search length
xor ch,ch
search2: push ax ;save record number
push cx ;save record count
call record_address ;get address of current record
mov cx,6 ;6 lines per record
search3: push cx ;save line count
push di ;save line address
mov cl,passes ;set number of passes per line
xor ch,ch
search4: push cx ;save pass count
push di ;save search address within line
mov cl,strlen ;number of bytes to compare
xor ch,ch
xor si,si ;point SI to input buffer
search5: lodsb ;get a byte from the input buffer
and al,0DFh ;capitalize it
mov bl,es:[di] ;get a byte from the record
and bl,0DFh ;capitalize it
inc di ;advance pointer
cmp al,bl ;are the two bytes identical?
jne nextpos ;no, then try next position
loop search5 ;yes, then try next byte
;
;A match was found. Clean up the stack and display the record.
;
add sp,10 ;delete last 5 words PUSHed
pop ax ;retrieve current record number
push ax ;push it back onto the stack
mov cl,numrec ;restart the record counter
xor ch,ch
inc cx
push cx ;shove it onto the stack
mov recptr,al ;set current record to this one
call show_record ;display new record
mov si,offset menuline5 ;display new menu line
call write_menu
searchkey: call getkey ;wait for a keypress
cmp al,13 ;ENTER key?
je nextrec ;yes, then continue search
cmp al,27 ;ESC key?
jne searchkey ;no, then ignore the keypress
pop cx ;clean up the stack
pop ax
jmp search_exit ;exit
;
;Advance to the next position and continue the string search.
;
nextpos: pop di ;retrieve address
pop cx ;retrieve pass count
inc di ;advance to next position on line
loop search4 ;loop back for another try
nextline: pop di ;retrieve line address
pop cx ;retrieve line count
add di,32 ;advance pointer to next line
loop search3 ;loop back
nextrec: pop cx ;retrieve record count
pop ax ;retrieve current record number
cmp al,numrec ;currently on last record?
je reset ;yes, then wrap around
inc al ;no, then advance record pointer
jmp short next1
reset: mov al,1 ;reset record pointer
next1: loop search2 ;reenter main loop
;
;All records were searched and no match was found.
;
mov si,offset menuline6 ;print message
call write_menu
search6: call getkey ;wait for a press of ESC
cmp al,27
jne search6
jmp search_exit ;exit
search endp
;
;------------------------------------------------------------------------------
;DIAL dials the phone number currently displayed.
;------------------------------------------------------------------------------
linectrl db ? ;Line Control Register value
divlsb db ? ;baud rate divisor LSB
divmsb db ? ;baud rate divisor MSB
intreg db ? ;Interrupt Enable Register value
;
dial proc near
cmp numrec,0 ;any records in memory?
jne dstart ;yes, then branch
dial_exit: ret ;no, then exit
;
;Save the current state of the COM port.
;
dstart: mov si,comport ;get UART base address
shl si,1
push es ;save ES
mov ax,bios_data ;then point it to BIOS data area
mov es,ax
assume es:bios_data
mov dx,rs232_base[si]
pop es ;restore ES
assume es:nothing
or dx,dx ;is this port installed?
je dial_exit ;no, then exit
add dx,3 ;point DX to Line Control Register
push dx ;save the address
in al,dx ;read LCR
mov linectrl,al ;store value for later
or al,80h ;set DLAB
out dx,al
sub dx,3 ;point DX to Divisor LSB Register
in al,dx ;read it
mov divlsb,al ;save it
inc dx ;point DX to Divisor MSB Register
in al,dx ;read it
mov divmsb,al ;save it
mov al,linectrl ;recover Line Control setting
and al,07Fh ;clear the high bit
add dx,2 ;point DX back to Line Control
out dx,al ;clear DLAB
sub dx,2 ;address Interrupt Enable Register
in al,dx ;read it
mov intreg,al ;and save it
;
;Initialize the COM port.
;
mov ah,0 ;initialize COM port
mov al,initstr ;baud rate and data format
mov dx,comport ;COM port identifier
int 14h
;
;Dial the phone number.
;
mov si,offset dialstr ;point DS:SI to 'ATDT' string
call sendcom ;output string to COM port
test ah,80h ;was the string sent?
jnz time_out ;no, then modem isn't ready
mov al,recptr ;get address of current record
call record_address
mov si,di
add si,128 ;point SI to 'Phone' line
mov cx,32 ;32 characters to check
dial1: lodsb ;get one character
cmp al,"," ;is it a comma?
je dial2 ;yes, then send it
cmp al,"0" ;less than ASCII zero?
jb dial3 ;yes, then ignore it
cmp al,"9" ;greater than ASCII 9?
ja dial3 ;yes, then ignore it
dial2: mov ah,1 ;output byte to COM port
int 14h
test ah,80h ;was the byte successfully output?
jnz time_out ;no, then modem isn't ready
dial3: loop dial1 ;loop until line is finished
mov ax,013Bh ;terminate with semicolon and CR
int 14h
mov ax,010Dh
int 14h
test ah,80h ;were the bytes transmitted?
jz dial5 ;yes, then continue
;
;Display 'Modem not ready' message and wait for ESC to be pressed.
;
time_out: mov si,offset menuline12 ;print message
call write_menu
dial4: call getkey ;wait for a press of ESC
cmp al,27
jne dial4
jmp dial8
;
;Wait for a press of the spacebar, then force the modem to hang up.
;
dial5: mov si,offset menuline10 ;display 'Pick up phone...'
call write_menu
dial6: call getkey ;wait for a press of the spacebar
cmp al,32
jne dial6
mov si,offset hangupstr ;point SI to 'ATH0' string
mov dx,comport ;specify COM port
call sendcom ;output it to the COM port
mov cx,8000h ;I/O delay
dial7: loop dial7
;
;Restore the COM port to its original state and exit.
;
dial8: pop dx ;retrieve UART address
mov al,80h ;set DLAB
out dx,al
sub dx,3 ;point DX to Divisor LSB
mov al,divlsb ;reset it
out dx,al
inc dx ;point DX to MSB
mov al,divmsb ;reset it
out dx,al
add dx,2 ;point DX to Line Control
xor al,al ;clear DLAB
out dx,al
sub dx,2 ;point DX to Interrupt Enable
mov al,intreg ;restore it
out dx,al
add dx,2 ;restore Line Control Register
mov al,linectrl
out dx,al
mov si,offset menuline1 ;restore menu line and exit
call write_menu
ret
dial endp
;
;------------------------------------------------------------------------------
;SENDCOM outputs an ASCIIZ string to the designated COM port.
;Entry: DS:SI - string address | Exit: AH bit 7 clear - string sent
; DX - 0 = COM1, 1 = COM2 | AH bit 7 set - time out
;------------------------------------------------------------------------------
sendcom proc near
lodsb ;get a byte
or al,al ;zero terminator?
je comexit ;yes, then exit
mov ah,1 ;output byte
int 14h
test ah,80h ;was byte transmitted?
jz sendcom ;yes, loop back for more
comexit: ret ;exit
sendcom endp
;
;------------------------------------------------------------------------------
;EDIT allows the current record to be edited.
;------------------------------------------------------------------------------
edit proc near
cmp numrec,0 ;any records to edit?
je edit1 ;no, then exit
mov al,recptr ;get current record number
call record_address ;get its address and position
mov slotno,al ;save position
push di ;save address
call delete_record ;delete it
pop di ;recover address
push di ;save it again
mov si,offset menuline9 ;address menu line text
call edit_record ;allow it to be edited
pop si ;place address in SI
jc no_entry ;branch if entry now blank
call find_position ;determine logical position
mov bl,slotno ;retrieve physical position
call insert_record ;insert record into the stack
mov recptr,cl ;modify current record number
edit1: ret ;exit
no_entry: cmp numrec,0 ;any records left after deletion?
je edit1 ;no, then we're done
mov al,numrec ;get number of records
cmp al,recptr ;RECPTR in range?
jae edit2 ;yes, then branch
dec recptr ;no, then modify it
edit2: call show_record ;display new current record
ret
edit endp
;
;------------------------------------------------------------------------------
;CREATE allows a new record to be created and inserted.
;------------------------------------------------------------------------------
create proc near
mov al,numrec ;retrieve number of records
cmp al,maxrec ;room for another record?
jne create1 ;yes, then branch
mov si,offset menuline7 ;no, then print error message
call write_menu
create0: call getkey ;wait for a press of ESC
cmp al,27
jne create0
mov si,offset menuline1 ;restore menu line
call write_menu
ret ;exit
create1: call clear_window ;clear the current display
xor al,al ;zero AL
call record_address ;get address of empty record slot
mov slotno,al ;save position
mov al,32 ;blank the record
mov cx,192
rep stosb
sub di,192 ;point DI back to start of record
push di ;save address
mov si,offset menuline3 ;set text address
call edit_record ;allow record to be edited
pop si ;get address in SI
jc blank_entry ;branch if new entry is blank
call find_position ;determine new record position
mov bl,slotno ;retrieve its physical position
call insert_record ;insert new record into stack
mov recptr,cl ;point RECPTR to new record
ret
blank_entry: cmp numrec,0 ;any records?
je blank1 ;no, then exit
call show_record ;display current record
blank1: ret
create endp
;
;------------------------------------------------------------------------------
;DELETE deletes the current record.
;------------------------------------------------------------------------------
delete proc near
cmp numrec,0 ;any records to delete?
je del_exit ;no, then exit
mov si,offset menuline2 ;request verification
call write_menu
del1: call getkey ;get keyboard response
cmp al,13 ;ENTER pressed?
je del2 ;yes, then continue
cmp al,27 ;ESC pressed?
jne del1 ;no, then get another keypress
del2: push ax ;save response
mov si,offset menuline1 ;restore menu line
call write_menu
pop ax ;retrieve response
cmp al,13 ;delete the record?
jne del_exit ;no
call delete_record ;delete current record
cmp numrec,0 ;any records left?
jne del3 ;yes, then branch
call clear_window ;no, then clear display
del_exit: ret ;exit
del3: mov al,numrec ;get record count
cmp al,recptr ;is RECPTR in range?
jae del4 ;yes, then branch
dec recptr ;no, then make sure it is
del4: call show_record ;display new current record
ret
delete endp
;
;------------------------------------------------------------------------------
;SAVE writes the data in memory to disk.
;------------------------------------------------------------------------------
save proc near
cmp numrec,0 ;any records to save?
jne fsave1 ;yes, then continue
ret ;no, then exit
fsave1: cmp fileflag,0 ;does a filespec exist?
jne fsave2 ;yes, then branch
;
;Read a filespec input from the keyboard.
;
getname: mov si,offset menuline13 ;print input prompt
call write_menu
xor di,di ;prepare for call to READLN
mov dx,0E1Ah
mov cl,34
call readln ;read the filespec
or cl,cl ;anything entered?
je save_exit ;no, then exit
mov fileflag,1 ;set filespec indicator
xor si,si ;copy filespec into buffer
mov di,offset filespec
xor ch,ch
rep movsb
mov byte ptr es:[di],0 ;zero last byte
;
;Open the file and write record data out to it.
;
fsave2: mov dx,offset filespec ;point DX to filespec
mov ah,3Ch ;open/create file
xor cx,cx ;normal attributes
int 21h
jc getname ;get new filespec if open failed
fsave3: mov bx,ax ;transfer file handle to BX
mov ah,40h ;write NUMREC byte to file
mov cx,1
mov dx,offset numrec
int 21h
jc save_error ;branch on error
cmp ax,1 ;byte successfully written?
jb diskfull ;no, then disk is full
mov al,1 ;initialize record number
mov cl,numrec ;get number of records to write
xor ch,ch
fsave4: push cx ;save count
push ax ;save record number
call record_address ;get address of current record
mov dx,di ;transfer it to DX
mov cx,192 ;192 bytes per record
mov ah,40h ;write one record
int 21h
mov dx,ax ;transfer byte count to DX
pop ax ;retrieve record number and count
pop cx
jc save_error ;branch on error
cmp dx,192 ;entire record written?
jb diskfull ;no, then disk is full
inc al ;next record
loop fsave4 ;loop until done
closefile: mov ah,3Eh ;close file
int 21h
save_exit: mov si,offset menuline1 ;restore menu line
call write_menu
ret ;exit
;
;An error was encountered during the save.
;
save_error: mov si,offset menuline11 ;print error message
push bx ;save file handle
call write_menu
pop bx ;retrieve file handle
error2: call getkey ;wait for a press of ESC
cmp al,27
jne error2
jmp short closefile ;close file and resume
;
;No room left on the disk.
;
diskfull: mov si,offset menuline8 ;print 'Disk full' message
push bx ;save file handle
call write_menu
pop bx ;retrieve file handle
full2: call getkey ;wait for a press of ESC
cmp al,27
jne full2
jmp short closefile ;and exit
save endp
;
;------------------------------------------------------------------------------
;DISABLE_CGA and ENABLE_CGA disable and enable CGA video output.
;------------------------------------------------------------------------------
disable_cga proc near
mov dx,3DAh ;address of Status Register
disable1: in al,dx ;get status
test al,8 ;vertical retrace active?
je disable1 ;no, then wait
sub dx,2 ;MSR address in DX
mov al,25h ;value to disable video
out dx,al ;disable video output
ret
disable_cga endp
;
enable_cga proc near
mov ah,15 ;get video mode
int 10h
mov bx,offset enable_values ;get value to enable display
xlat ;value in AL
mov dx,3D8h ;MSR address
out dx,al ;enable video output
ret
enable_cga endp
;
;------------------------------------------------------------------------------
;GETKEY waits for a keypress and returns the keycode in AX.
;Exit: AX - keycode
;------------------------------------------------------------------------------
getkey proc near
mov ah,1 ;check keyboard buffer
int 16h
jne getkey1 ;jump if buffer contains a keycode
int 28h ;no key pressed - issue int 28h
jmp getkey ;loop back to try again
getkey1: mov ah,0 ;get keycode from buffer
int 16h
ret ;exit with keycode in AX
getkey endp
;
;------------------------------------------------------------------------------
;INSERT_RECORD inserts a record into the stack.
;Entry: BL - slot number
; CL - index number
;------------------------------------------------------------------------------
insert_record proc near
push cx ;save index number
mov di,offset index_table ;point DI to index table
mov al,cl ;get index number in AL for search
mov cl,maxrec ;set counter
xor ch,ch
insert1: cmp [di],al ;index less than new index?
jb insert2 ;yes, then branch
inc byte ptr [di] ;increment index
insert2: inc di ;advance DI to next index
loop insert1 ;loop until all indexes examined
pop cx ;retrieve new index number
xor bh,bh ;byte to word in BX
mov di,offset index_table ;point DI to index table
mov [di+bx],cl ;deposit new index into table
inc numrec ;increment record count by 1
ret
insert_record endp
;
;------------------------------------------------------------------------------
;DELETE_RECORD deletes the record indexed by RECPTR.
;------------------------------------------------------------------------------
delete_record proc near
mov al,recptr ;search for current record slot
mov di,offset index_table
mov cl,maxrec
xor ch,ch
repne scasb
dec di ;back to matching byte
mov byte ptr [di],0 ;zero current index
mov al,recptr ;get current record number
mov di,offset index_table ;point DI to index table
mov cl,maxrec ;set counter
xor ch,ch
delrec1: cmp [di],al ;index less than current index?
jb delrec2 ;yes, then branch
dec byte ptr [di] ;no, decrement index
delrec2: inc di ;advance to next index
loop delrec1 ;loop until all records examined
dec numrec ;decrement record count by 1
ret
delete_record endp
;
;------------------------------------------------------------------------------
;EDIT_RECORD allows the record addressed by ES:DI to be edited.
;Entry: ES:DI - record address | Exit: CF clear - record valid
; DS:SI - menu line text string | CF set - record blank
;------------------------------------------------------------------------------
edit_record proc near
push di ;save starting address
call write_menu ;write new menu line
mov bh,video_page ;set BH for video calls
mov ah,2 ;set initial cursor position
mov dx,071Bh
int 10h
call show_cursor ;display the cursor
;
;Wait for a keypress.
;
editrec1: call getkey ;get a keypress
or al,al ;extended code?
jne editrec2 ;no, then branch
jmp short extend ;goto extended code handler
editrec2: cmp al,8 ;backspace key?
je bspace
cmp al,13 ;ENTER key?
je enter
cmp al,32 ;ASCII code less than 32?
jb editrec1 ;yes, then ignore it
;
;Process a press of a character key.
;
cmp dl,59 ;at the end of the line?
je editrec1 ;yes, then ignore keypress
stosb ;deposit character in record
mov ah,10 ;then print it
mov cx,1
int 10h
mov ah,2 ;advance the cursor
inc dl
int 10h
jmp editrec1 ;return for more
;
;Process a press of the BACKSPACE key.
;
bspace: cmp dl,27 ;any characters to delete?
je editrec1 ;no, then ignore keypress
mov ah,2 ;move cursor back one space
dec dl
int 10h
mov ax,0A20h ;print a space character
mov cx,1
int 10h
dec di ;decrement buffer pointer by 1
mov byte ptr es:[di],32 ;insert an ASCII space
jmp editrec1
;
;Process a press of the ENTER key.
;
enter: mov al,dl ;reset DI to beginning of line
xor ah,ah
sub ax,27
sub di,ax
inc dh ;advance row number
add di,32 ;advance pointer
cmp dh,13 ;wrap around if necessary
jne enter1
mov dh,7
sub di,192
enter1: mov dl,27 ;home the cursor
mov ah,2
int 10h
jmp editrec1 ;return to input loop
;
;Process a press of either Cursor-Left or Cursor-Right.
;
extend: cmp ah,75 ;cursor left key?
jne ext2 ;no, then branch
cmp dl,27 ;already at left end of field?
je ext1 ;yes, then ignore keypress
mov ah,2 ;move cursor back one space
dec dl
int 10h
dec di ;decrement buffer pointer
ext1: jmp editrec1 ;return
ext2: cmp ah,77 ;cursor right key?
jne ext3 ;no, then branch
cmp dl,59 ;cursor in last column?
je ext1 ;yes, then ignore keypress
mov ah,2 ;advance cursor
inc dl
int 10h
inc di ;increment buffer pointer
jmp editrec1 ;return
;
;Process a press of either Cursor-Up or Cursor-Down.
;
ext3: cmp ah,72 ;cursor up key?
jne ext5 ;no, then branch
dec dh ;decrement row number
sub di,32 ;set pointer to previous line
cmp dh,6 ;wrap around if necessary
jne ext4
mov dh,12
add di,192
ext4: mov ah,2 ;move the cursor
int 10h
jmp editrec1 ;return for another keypress
ext5: cmp ah,80 ;cursor down key?
jne ext6 ;no, then branch
inc dh ;increment row number
add di,32 ;set pointer to next line
cmp dh,13 ;wrap around if necessary
jne ext4
mov dh,7
sub di,192
jmp ext4 ;move cursor and return
;
;End the edit routine when F1 is pressed.
;
ext6: cmp ah,59 ;F1 key?
jne ext4 ;no, then ignore keypress
mov ah,1 ;hide the cursor
mov ch,20h
int 10h
mov si,offset menuline1 ;restore menu line
call write_menu
pop di ;recover starting address
mov al,32 ;ASCII space character
mov cx,192 ;192 bytes per record
repe scasb ;check for non-space character
jne ok ;OK if non-space found
stc ;set CF to indicate blank entry
ret
ok: clc ;clear CF to indicate valid record
ret
edit_record endp
;
;------------------------------------------------------------------------------
;FIND_POSITION returns the new index of the record addressed by SI.
;Entry: SI - record address | Exit: CL - record number
;------------------------------------------------------------------------------
find_position proc near
mov cl,1 ;set index for first record
cmp numrec,0 ;any records to examine?
je find_exit ;no, then exit
find1: mov al,cl ;get index in AL
push cx ;save it
call record_address ;get address of next record
push si ;save new record address
mov cx,32 ;32 bytes per record
find2: cmpsb ;compare records
ja next_record ;check next record
jb slot_found ;alphabetical slot found
loop find2 ;goto next byte if these are equal
jmp short slot_found ;slot found if all equal
next_record: pop si ;clean up the stack
pop cx
inc cl ;next record number
cmp cl,numrec ;all records searched?
jbe find1 ;no, then loop back for more
find_exit: ret ;yes, then we're done
slot_found: pop si ;clean up the stack
pop cx
ret
find_position endp
;
;------------------------------------------------------------------------------
;SHOW_RECORD displays the record pointed to by RECPTR.
;------------------------------------------------------------------------------
show_record proc near
mov al,recptr ;get current record number
call record_address ;get record address in DI
mov si,di ;transfer it to SI
mov bl,record_attr ;set attribute to be used
mov dx,071Bh ;set initial cursor position
mov cx,6 ;6 lines to display
show1: push cx ;save line counter
push dx ;save cursor position
mov cx,32 ;32 characters per line
call writeln ;display one line
pop dx ;retrieve cursor address
inc dh ;increment row number
pop cx ;retrieve line counter
loop show1 ;loop until done
ret
show_record endp
;
;------------------------------------------------------------------------------
;RECORD_ADDRESS returns the offset address and slot number of a record.
;Entry: AL - record number | Exit: DI - record address
; | AL - slot number
;------------------------------------------------------------------------------
record_address proc near
mov di,offset index_table ;point DI to index table
mov cl,maxrec ;set counter
xor ch,ch
repne scasb ;search for current record number
inc cx ;increment counter
mov al,maxrec ;calculate offset address in AX
sub al,cl
push ax ;save slot number
mul record_length
add ax,offset data_buffer
mov di,ax ;transfer address to DI
pop ax ;recover slot number
ret
record_address endp
;
;------------------------------------------------------------------------------
;WRITE_MENU displays a line of text on the window's menu line.
;Entry: DS:SI - address of text
;------------------------------------------------------------------------------
write_menu proc near
mov ah,2 ;position the cursor
mov dx,0E14h
mov bh,video_page
int 10h
mov ax,0920h ;erase current menu line
mov bl,menu_attr
mov cx,40
int 10h
wm1: lodsb ;get a character
or al,al ;exit if it's the delimiter
je wm2
mov ah,0Eh ;write the character
int 10h
jmp short wm1 ;loop until done
wm2: ret
write_menu endp
;
;------------------------------------------------------------------------------
;WRITELN displays a string.
;Entry: DS:SI - string address
; BL - attribute
; CX - string length
; DH,DL - starting row and column
;------------------------------------------------------------------------------
writeln proc near
mov bh,video_page ;set page number for output
write1: mov ah,2 ;position cursor
int 10h
lodsb ;get one byte
push cx ;save count
mov cx,1 ;zero repetitions
mov ah,9 ;int 10h function - write c/a
int 10h ;write character/attribute
inc dl ;advance cursor
pop cx ;retrieve character count
loop write1 ;loop until done
ret
writeln endp
;
;------------------------------------------------------------------------------
;READLN accepts input of a string entered from the keyboard.
;Entry: ES:DI - buffer address | Exit: CL - string length
; DH,DL - cursor start position |
; CL - max length accepted |
;------------------------------------------------------------------------------
maxlen db ? ;maximum string length
;
readln proc near
mov maxlen,cl ;save max length
mov ah,2 ;set cursor to start position
mov bh,video_page
int 10h
call show_cursor ;display the cursor
xor cl,cl ;initialize counter
;
;Wait for a keypress.
;
read1: call getkey ;get a character
cmp al,13 ;ENTER key?
je read_exit ;yes, then exit
cmp al,27 ;ESC key?
jne read2 ;no, then branch
xor cl,cl ;zero length
jmp short read_exit ;exit
read2: cmp al,8 ;backspace key?
je backspace ;yes, then do backspace function
cmp al,32 ;ASCII 32 or greater?
jb read1 ;no, then ignore it
cmp al,126 ;ASCII 126 or less?
ja read1 ;no, then ignore keypress
cmp cl,maxlen ;room for another entry?
je read1 ;no, then ignore it
;
;Process the press of a character key.
;
stosb ;deposit character in buffer
push cx ;save character count
mov ah,10 ;print the character
mov cx,1
int 10h
inc dl ;advance the cursor
mov ah,2
int 10h
pop cx ;retrieve count
inc cl ;update count
jmp read1 ;go back for more
;
;Process a press of the BACKSPACE key.
;
backspace: or cl,cl ;any characters to delete?
je read1 ;no, then ignore keystroke
push cx ;save count
dec dl ;move cursor back one space
mov ah,2
int 10h
mov ah,10 ;print a space character
mov al,32
mov cx,1
int 10h
pop cx ;retrieve count
dec cl ;decrement it
dec di ;decrement buffer pointer
jmp read1 ;go back for more
;
;Hide the cursor and return.
;
read_exit: mov ah,1 ;hide the cursor
mov ch,20h
int 10h
ret
readln endp
;
;------------------------------------------------------------------------------
;SHOW_CURSOR displays the cursor and discounts EGA cursor emulation logic.
;Entry: NEW_CURSOR - starting and ending scan lines
;------------------------------------------------------------------------------
show_cursor proc near
cmp adapter,2 ;is an EGA currently active?
jne cursor1 ;no, then branch
push es ;save ES
mov ax,bios_data ;point ES to BIOS data area
mov es,ax
assume es:bios_data
push infobyte ;save EGA info byte
or ega_info,1 ;disable EGA cursor emulation
cursor1: mov ah,1 ;display the cursor
mov cx,new_cursor
int 10h
cmp adapter,2 ;is an EGA active?
jne cursor_exit ;no, then exit
pop infobyte ;restore EGA info byte
pop es ;restore ES
assume es:nothing
cursor_exit: ret
show_cursor endp
;
;------------------------------------------------------------------------------
;CLEAR_WINDOW clears the record currently displayed in the window.
;------------------------------------------------------------------------------
clear_window proc near
mov ax,0600h ;interrupt 10h, function 6
mov cx,071Bh
mov dx,0C3Bh
mov bh,record_attr
int 10h
ret
clear_window endp
;
;------------------------------------------------------------------------------
;IOSET vectors interrupts 1Bh, 23h and 24h to internal handlers. IORESET
;restores the original vector values.
;------------------------------------------------------------------------------
ioset proc near
push es ;save ES
mov ax,351Bh ;get interrupt 1Bh vector
int 21h
mov old1Bh_segment,es ;save it
mov old1Bh_offset,bx
mov ah,25h ;point it to an IRET instruction
mov dx,offset ioexit
int 21h
mov ax,3523h ;get interrupt 23h vector
int 21h
mov old23h_segment,es ;save it
mov old23h_offset,bx
mov ah,25h ;point it to an IRET instruction
mov dx,offset ioexit
int 21h
mov ax,3524h ;get interrupt 24h vector
int 21h
mov old24h_segment,es ;save it
mov old24h_offset,bx
mov ah,25h ;then set it to IOERR routine
mov dx,offset ioerr
int 21h
pop es ;restore ES
ret
ioset endp
;
ioreset proc near
mov ax,2524h ;restore interrupt 24h vector
mov dx,old24h_offset
push ds
assume ds:nothing
mov ds,old24h_segment
int 21h
mov ax,2523h ;restore interrupt 23h vector
mov dx,old23h_offset
mov ds,old23h_segment
int 21h
mov ax,251Bh ;restore interrupt 1Bh vector
mov dx,old1Bh_offset
mov ds,old1Bh_segment
int 21h
pop ds
assume ds:code
ret
ioreset endp
;
;------------------------------------------------------------------------------
;FINISH loads the data file, resets interrupt vectors, and terminates.
;------------------------------------------------------------------------------
finish proc near
;
;Open the specified data file for reading.
;
mov ax,3D00h ;open file for reading
mov dx,offset filespec ;point DX to ASCIIZ filespec
int 21h
jnc finish3 ;branch if no error
mov ah,9 ;print 'File not found'
mov dx,offset errmsg1
int 21h
cmp reload,0 ;was this an attempted reload?
je endfin ;no, then exit
mov al,old_numrec ;yes, then restore parameters
mov es:[numrec],al
mov al,old_recptr
mov es:[recptr],al
mov al,old_fileflag
mov es:[fileflag],al
endfin: ret ;and exit
;
;Load the data file into memory.
;
finish3: mov bx,ax ;transfer file handle to BX
push ds ;exchange DS and ES
push es
pop ds
pop es
mov ah,3Fh ;read record count byte
mov cx,1
mov dx,offset numrec
int 21h
jc close ;branch on error
mov al,ds:[maxrec] ;make sure NUMREC <= MAXREC
cmp al,ds:[numrec]
jae finish4
mov ds:[numrec],al ;adjust if it isn't
finish4: mov al,ds:[numrec] ;calculate number of bytes to read
mul record_length
mov cx,ax ;transfer number of bytes to CX
mov ah,3Fh ;DOS function 3Fh - read file
mov dx,offset data_buffer ;point DX to buffer area
int 21h ;read all records from disk
close: mov ah,3Eh ;close file
int 21h
mov ds:[fileflag],1 ;set filespec flag
push ds ;swap DS and ES again
push es
pop ds
pop es
;
;Initialize the record index table.
;
finish5: mov di,offset index_table ;point DI to table area
xor al,al ;zero AL
mov cl,es:[maxrec] ;set counter
xor ch,ch
rep stosb ;zero all bytes
mov cl,es:[numrec] ;set CX to number of records
xor ch,ch
jcxz finish7 ;exit if there are none
mov di,offset index_table ;reset DI
mov al,1 ;initialize AL
finish6: stosb ;set one index byte
inc al ;increment index
loop finish6 ;loop until done
;
;Copy new filespec into old data space if this is a reload.
;
finish7: cmp reload,0 ;is this a reload
je finish8 ;no, then branch
mov si,offset filespec ;point SI and DI to filespec areas
mov di,si
mov cx,126 ;set counter
rep movsb ;transfer text
ret ;done - exit
;
;Save and replace all required interrupt vectors.
;
finish8: mov ax,3508h ;get interrupt 8 vector
int 21h
mov old8h,bx ;save it
mov old8h[2],es
mov ah,25h ;point it to the TIMER routine
mov dx,offset timer
int 21h
mov ax,3509h ;get interrupt 9 vector
int 21h
mov old9h,bx ;save it
mov old9h[2],es
mov ah,25h ;point it to KEYBOARD routine
mov dx,offset keyboard
int 21h
mov ax,3510h ;get interrupt 10h vector
int 21h
mov old10h,bx ;save it
mov old10h[2],es
mov ah,25h ;point it to VIDEO
mov dx,offset video
int 21h
mov ax,3513h ;get interrupt 13h vector
int 21h
mov old13h,bx ;save it
mov old13h[2],es
mov ah,25h ;point it to BDISK
mov dx,offset bdisk
int 21h
mov ax,3528h ;get interrupt 28h vector
int 21h
mov old28h,bx ;save it
mov old28h[2],es
mov ah,25h ;point it to BACKPROC
mov dx,offset backproc
int 21h
;
;Calculate amount of memory to reserve and terminate-but-stay-resident.
;
mov dx,offset program ;display notice and hot key
mov ah,9 ;with DOS function 9
int 21h
mov al,maxrec ;get max number of records
mul record_length ;multiply by 192
mov dx,ax ;transfer figure to DX
add dx,(offset data_buffer - offset code + 15)
mov cl,4 ;convert bytes to paragraphs
shr dx,cl
mov ax,3100h ;load function and return codes
int 21h ;terminate-but-stay-resident
finish endp
;
;-----------------------------------------------------------------------------
;Data space to be used after Cardfile is resident in memory.
;-----------------------------------------------------------------------------
pc = $
screen_buffer = pc ;video memory buffer
pc = pc + 10 * 44 * 2
index_table = pc ;record index table
pc = pc + 512
filespec = pc ;file specification
pc = pc + 128
data_buffer = pc ;record buffer
;
;------------------------------------------------------------------------------
;INITIALIZE prepares the program for residency.
;------------------------------------------------------------------------------
initialize proc near
assume ds:code
errmsg1 db 13,10,"File not found",13,10,"$"
errmsg2 db 13,10,"Critical Error Flag not found",13,10,"$"
old_numrec db ?
old_recptr db ?
old_fileflag db ?
;
;See if the program is already resident in memory.
;
init1: mov word ptr [begin],0 ;zero word to avoid false match
xor bx,bx ;initialize search segment
mov ax,cs ;record current segment in AX
init2: inc bx ;increment search segment
cmp ax,bx ;reached current segment?
je init3 ;yes, then this is the first load
mov es,bx ;point ES to search segment
mov si,offset begin ;point SI and DI to ID offset
mov di,si
mov cx,16 ;check 16 characters
cld ;clear DF
repe cmpsb ;compare the strings
jne init2 ;continue search if compare failed
;
;Cardfile is already installed. Set the reload flag and save parameters.
;
mov reload,1 ;set flag
mov al,es:[numrec] ;save parameters
mov old_numrec,al
mov al,es:[recptr]
mov old_recptr,al
mov al,es:[fileflag]
mov old_fileflag,al
mov es:[numrec],0 ;initialize counters and flags
mov es:[recptr],1
mov es:[fileflag],0
jmp short parse ;branch to parsing code
;
;Determine which version of DOS is running.
;
init3: mov ah,30h ;DOS function 30h
int 21h
mov dos_version,al ;major version number
;
;Get and save the address of the INDOS flag.
;
mov ah,34h ;function 34h
int 21h ;get address
mov dos_segment,es ;save segment
mov indos_offset,bx ;save offset
;
;Get and save the address of the critical error flag.
;
mov ax,3E80h ;CMP opcode
mov cx,2000h ;max search length
mov di,bx ;start at INDOS address
init4: repne scasw ;do the search
jcxz init5 ;branch if search failed
cmp byte ptr es:[di+5],0BCh ;verify this is it
je found ;branch if it is
jmp init4 ;resume loop if it's not
init5: mov cx,2000h ;search again
inc bx ;search odd addresses this time
mov di,bx
init6: repne scasw ;look for the opcode
jcxz notfound ;not found if loop expires
cmp byte ptr es:[di+5],0BCh ;verify this is it
je found
jmp init6
notfound: mov ah,9 ;flag not found
mov dx,offset errmsg2
int 21h
ret
found: mov ax,es:[di] ;get flag offset address
mov errflag_offset,ax ;save it
push cs ;reset ES to the code segment
pop es
;
;Parse the command line and create a complete filespec.
;
parse: mov di,82h ;point DI to command line text
cmp byte ptr [di-2],2 ;less than 2 characters entered?
jnb parse0 ;no, then continue
jmp finish5 ;yes, then skip load routine
parse0: mov si,di ;point SI to command line text
mov di,offset filespec ;point DI to buffer
parse1: cmp byte ptr [si],32 ;advance to first non-space
jne parse2
inc si
jmp parse1
parse2: cmp byte ptr [si+1],":" ;leading drive specifier?
je parse4 ;yes, then filespec is complete
mov ah,19h ;get current drive
int 21h
add al,65 ;convert to ASCIIZ
mov ah,":" ;complete drive specifier
mov word ptr [di],ax ;write drive spec to buffer
add di,2 ;advance DI
cmp byte ptr [si],"\" ;leading backslash?
je parse4 ;yes, then filespec is complete
mov byte ptr [di],"\" ;fill in the backslash
inc di
push si ;save SI and DI
push di
mov ah,47h ;get current path
mov si,di
xor dl,dl ;default drive
int 21h ;append path to drive spec
pop di ;restore SI and DI
pop si
cmp byte ptr [di],0 ;anything returned?
je parse4 ;no, then filespec is complete
parse3: inc di ;advance to end of string
cmp byte ptr [di],0
jne parse3
mov byte ptr [di],"\" ;insert trailing backslash
inc di
parse4: mov al,[si] ;append entry to filespec string
cmp al,13
je parse5
mov [di],al
inc si
inc di
jmp parse4
parse5: mov byte ptr [di],0
jmp finish ;load data file and exit
initialize endp
;
code ends
end begin